-------------NoteCard Maker------------
A 4am crack                  2016-03-01
---------------------------------------

Name: NoteCard Maker
Genre: productivity
Year: 1985
Authors: Matthew Osber, Jay Roberts,
  Wendy Spitzer, Norma Arnow, Susan
  Christie Thomas
Publisher: Grolier
Media: 2 single-sided 5.25-inch disks
OS: Apple Pascal
Previous cracks: none

The disks are labeled "program" and
"tutorial". Both are bootable. I'll
start with disk 1.

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  fails on first pass

Locksmith Fast Disk Backup
  unable to read track $03, copy
  displays title and credits, then
  prints "THIS IS A DEFECTIVE DISK"

EDD 4 bit copy (no sync, no count)
  same as Locksmith FDB

Copy ][+ nibble editor
  T03 appears to be almost entirely
  sync bytes (all $FF, no data, no
  sectors per se, no structure at all)

Disk Fixer
  unable to read T03 under any
  combination of parameters

Why didn't COPYA work?
  T03 is unreadable because it does not
  have a standard sector structure

Why didn't Locksmith FDB work?
  Probably a nibble check during boot.
  (Disks do not simply call themselves
  out as defective unless someone tells
  them to.)

Why didn't my EDD copy work?
  ditto

Next steps:

  1. Find nibble check and disable it
  2. There is no step 2 (I hope)

                   ~

               Chapter 1
         In Which We Get Lucky


My non-working copy is pretty clear why
it's not running. Disks do not simply
print "THIS IS A DEFECTIVE DISK" for no
reason. There's a runtime protection
check somewhere.

One thing that all on-disk protection
checks have in common is they need to
turn on the drive motor by accessing a
specific address in the $C0xx range.
For slot 6, it's $C0E9, but to allow
disks to boot from any slot, developers
usually use code like this:

  LDX <slot number x 16>
  LDA $C089,X

There's nothing that says where the
slot number has to be, although the
disk controller ROM routine uses zero
page $2B and lots of disks just reuse
that. There's also nothing that says
you have to use the X-register as the
index, or that you must use the
accumulator as the load register. But
most RWTS code does, out of convention
I suppose (or possibly fear of messing
up such low-level code in subtle ways).

Also, since developers don't actually
want people finding their protection-
related code, they may try to encrypt
it or obfuscate it to prevent people
from finding it. But eventually, the
code must exist and the code must run,
and it must run on my machine, and I
have the final say on what my machine
does or does not do.

But sometimes you get lucky.

Turning to my trusty Disk Fixer sector
editor, I search my non-working copy
(disk 1) for "BD 89 C0", which is the
opcode sequence for "LDA $C089,X".

[Disk Fixer]
  ["F"ind]
    ["H"ex]
      ["BD 89 C0"]

                 --v--

------------- DISK SEARCH --------------

$04/$0E-$13   $1A/$08-$4A   $22/$0B-$53


             PRESS [RETURN]

                 --^--

T04,S0E appears to be part of a
legitimate RWTS. (T04,S0C and T04,S0D
contain code to read and write standard
16-sector disks.) T22,S0B and its
surrounding sectors are similarly
unsuspicious.

T1A,S08 doesn't contain much code, but
on its neighbor -- T1A,S09 -- I hit
paydirt.

                   ~

               Chapter 2
        In Which We Roll Around
              In Paydirt


I'm working entirely in my trusty Disk
Fixer sector editor, so the disassembly
listing looks slightly different than
the one I'd get in the monitor.

                 --v--

T1A,S09
----------- DISASSEMBLY MODE ----------
; standard pattern for Pascal programs
; to call a linked assembly language
; routine
002E:68             PLA
002F:8D 67 01       STA   $0167
0032:68             PLA
0033:8D 68 01       STA   $0168
0036:A2 60          LDX   #$60
0038:86 03          STX   $03

; turn on the drive motor (not shown)
003A:20 1C 01       JSR   $011C

; seek to a specific track (not shown)
003D:A0 04          LDY   #$04
003F:A9 06          LDA   #$06
0041:20 AD 00       JSR   $00AD

; In Pascal, linked assembly language
; routines are stored as if they're on
; zero page; the P-code interpreter
; munges the addresses at runtime. This
; routine is offset by $002E on disk,
; so this is calling what is listed at
; $005A below.
0044:20 2C 00       JSR   $002C

; seek back (not shown)
0047:A0 06          LDY   #$06
0049:A9 04          LDA   #$04
004B:20 AD 00       JSR   $00AD

; turn off drive motor
004E:BD 88 C0       LDA   $C088,X

; restore stack and exit via RTS
0051:AD 68 01       LDA   $0168
0054:48             PHA
0055:AD 67 01       LDA   $0167
0058:48             PHA
0059:60             RTS

OK, whatever is going on, it's all
happening in the subroutine at $005A.

; main entry point --
; try forever to find a $D5 nibble
005A:BD 8C C0       LDA   $C08C,X
005D:10 FB          BPL   $005A
005F:48             PHA
0060:68             PLA
0061:C9 D5          CMP   #$D5
0063:D0 F5          BNE   $005A

; initialize counter
0065:A0 00          LDY   #$00
0067:8C 65 01       STY   $0165

; look for some weird bitstream
006A:BD 8C C0       LDA   $C08C,X
006D:10 FB          BPL   $006A
006F:C9 D5          CMP   #$D5
0071:F0 0F          BEQ   $0082
0073:C9 F7          CMP   #$F7
0075:D0 01          BNE   $0078
0077:C8             INY

; increment counter
0078:18             CLC
0079:6D 65 01       ADC   $0165
007C:8D 65 01       STA   $0165

; this jumps back to offset $006A
007F:4C 3C 00       JMP   $003C

; this is a typo/bug -- it should be
; transferring Y to A, not X (X is
; the boot slot x16, Y is the counter
; that's counting nibbles)
0082:8A             TXA
0083:F0 E0          BEQ   $0065

; look for sync byte ($FF)
0085:BD 8C C0       LDA   $C08C,X
0088:10 FB          BPL   $0085
008A:48             PHA
008B:68             PLA
008C:C9 FF          CMP   #$FF
008E:F0 F5          BEQ   $0085

; if first non-$FF nibble is $D5, fail
0090:C9 D5          CMP   #$D5
0092:F0 2C          BEQ   $00C0

; skip over 6 nibbles
0094:A0 05          LDY   #$05
0096:BD 8C C0       LDA   $C08C,X
0099:10 FB          BPL   $0096
009B:48             PHA
009C:68             PLA
009D:88             DEY
009E:D0 F6          BNE   $0096

; more sync bytes
00A0:BD 8C C0       LDA   $C08C,X
00A3:10 FB          BPL   $00A0
00A5:48             PHA
00A6:68             PLA
00A7:C9 FF          CMP   #$FF
00A9:F0 F5          BEQ   $00A0

; $D5 at this point = fail
00AB:C9 D5          CMP   #$D5
00AD:D0 11          BNE   $00C0

; non-$FF at this point = fail
00AF:BD 8C C0       LDA   $C08C,X
00B2:10 FB          BPL   $00AF
00B4:C9 FF          CMP   #$FF
00B6:D0 08          BNE   $00C0

; check the counter
00B8:AD 65 01       LDA   $0165
00BB:C9 10          CMP   #$10
00BD:D0 01          BNE   $00C0
00BF:60             RTS

; $002E + $0095 = $00C3, so this is
; jumping to the next line
00C0:4C 95 00       JMP   $0095

; failure path -- decrypt error message
; and display it
00C3:A0 17          LDY   #$17
00C5:B9 4D 01       LDA   $014D,Y
00C8:49 BB          EOR   #$BB
00CA:99 08 07       STA   $0708,Y
00CD:88             DEY
00CE:10 F5          BPL   $00C5
00D0:AD 54 C0       LDA   $C054
00D3:AD 51 C0       LDA   $C051
00D6:78             SEI

; destroy stack while looping forever
00D7:48             PHA

; jumps to previous line (offset $00D7)
00D8:4C A9 00       JMP   $00A9

                 --^--

If the protection check passes, we
return to the Pascal program. If it
fails, we display an error message and
hang. This matches the behavior I saw
on my non-working copy.

There is one side effect -- the value
of the counter at $0165. But this value
is never passed back to the Pascal
runtime, so I'm guessing it's strictly
internal to the protection routine. If
that's true, I should be able to put an
"RTS" at the very beginning (offset
$002E in the listing above) and bypass
the entire protection check.

Disk 1:
T1A,S09,$2E change "68" to "60"

]PR#6
...works...

Disk 2 has identical protection, but
the protection check is in a different
place on disk.

Disk 2:
T1C,S00,$46 change "68" to "60"

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 624
------------------EOF------------------
